home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / slip / dynix / sl / sys / net / if_sl.c next >
Encoding:
C/C++ Source or Header  |  1988-09-26  |  12.5 KB  |  582 lines

  1. /*
  2.  * Sequent Balance Serial Line IP Driver
  3.  *
  4.  * This driver is a modified version of the 7.1 (Berkeley) version. The
  5.  * original code was developed by Rick Adams and subsequently modified
  6.  * by Chris Torek for 4.3BSD.  Other changes made at Berkeley based in 
  7.  * part on code by Kirk Smith. The Sequent port was done by Phil Klimbal.
  8.  *
  9.  * Authors Addresses:
  10.  *     Rick Adams                Chris Torek
  11.  *     rick@seismo.css.gov            chris@mimsy.umd.edu
  12.  *     seismo!rick                umcp-cs!chris
  13.  *
  14.  *    Kirk Smith                Phil Klimbal
  15.  *     ks@ecn.purdue.edu            klimbal@riacs.edu
  16.  *     pur-ee!ks                riacs!klimbal
  17.  *
  18.  * Copyright (C) 1987 Research Institute for Advanced Computer Science.
  19.  * All rights reserved.  The RIACS Software Policy contains specific
  20.  * terms and conditions on the use of this software, and must be
  21.  * distributed with any copies.  This file may be redistributed.  This
  22.  * copyright and notice must be preserved in all copies made of this file.
  23.  */
  24.  
  25. #include "../h/param.h"
  26. #include "../h/mutex.h"
  27. #include "../machine/gate.h"
  28. #include "../balance/engine.h"
  29. #include "../h/vmmeter.h"       /* for plocal.h */
  30. #include "../h/vmsystm.h"       /* for plocal.h */
  31. #include "../machine/pte.h"     /* for plocal.h */
  32. #include "../machine/vmparam.h" /* for plocal.h */
  33. #include "../machine/plocal.h"
  34. #include "../machine/intctl.h"
  35. #include "../h/time.h"
  36. #include "../h/mbuf.h"
  37. #include "../h/buf.h"
  38. #include "../h/dk.h"
  39. #include "../h/socket.h"
  40. #include "../h/ioctl.h"
  41. #include "../h/file.h"
  42. #include "../h/tty.h"
  43. #include "../h/errno.h"
  44.  
  45. #include "../net/if.h"
  46. #include "../net/netisr.h"
  47. #include "../net/route.h"
  48. #include "../net/if_sl.h"
  49.  
  50. #if INET
  51. #include "../netinet/in.h"
  52. #include "../netinet/in_systm.h"
  53. #include "../netinet/in_var.h"
  54. #include "../netinet/ip.h"
  55. #endif
  56.  
  57.  
  58. /*
  59.  * Called from boot code to establish sl interfaces.
  60.  */
  61. slboot(nsl)
  62.         u_long nsl;
  63. {
  64.     register struct sl_softc *sc;
  65.     register int i; 
  66.  
  67.     /* Allocate pointers for sl_softc structures */
  68.     sl_softc = (struct sl_softc **)calloc((nsl+1) * sizeof(u_long)); 
  69.  
  70.     for (i=0; i < nsl; i++) {
  71.         sl_softc[i] = (struct sl_softc *)calloc(1 * sizeof(struct sl_softc));
  72.         sc = sl_softc[i];
  73.         sc->sc_if.if_name = "sl";
  74.         sc->sc_if.if_unit = i;
  75.         sc->sc_if.if_mtu = SLMTU;
  76.         sc->sc_if.if_flags = IFF_POINTOPOINT;
  77.         sc->sc_if.if_ioctl = slioctl;
  78.         sc->sc_if.if_output = sloutput;
  79.         sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen;
  80.         init_lock(&sc->sc_if.if_snd.ifq_lock, G_NETISR);
  81.         init_lock(&sc->softc_lock, G_NETISR);
  82.         if_attach(&sc->sc_if);
  83.     }
  84. }
  85.  
  86. /*
  87.  * Line specific open routine.
  88.  * Attach the given tty to the first available sl unit.
  89.  */
  90. /* ARGSUSED */
  91. slopen(dev, tp)
  92.     dev_t dev;
  93.     register struct tty *tp;
  94. {
  95.     register struct sl_softc *sc;
  96.     register int i;
  97.     spl_t s;
  98.  
  99.     if (!suser())
  100.         return (EPERM);
  101.     if (tp->t_line == SLIPDISC)
  102.         return (EBUSY);
  103.  
  104.     for (i = 0; (sc=sl_softc[i]) != NULL; i++) {
  105.         s = p_lock(&sc->softc_lock, SPLIMP);    
  106.         if (sc->sc_ttyp == NULL) {
  107.             sc->sc_flags = 0;
  108.             sc->sc_ilen = 0;
  109.             if (slinit(sc) == 0) {
  110.                 v_lock(&sc->softc_lock, s);
  111.                 return (ENOBUFS);
  112.             }
  113.             sc->sc_dev = tp->t_dev;
  114.             sc->sc_ttyp = tp;
  115.  
  116.             /* reset interface stats */
  117.             sc->sc_if.if_ipackets = 0;
  118.             sc->sc_if.if_ierrors = 0;
  119.             sc->sc_if.if_opackets = 0;
  120.             sc->sc_if.if_oerrors = 0;
  121.             sc->sc_if.if_collisions = 0;
  122.  
  123.             v_lock(&sc->softc_lock, s);
  124.             ttyflush(tp, FREAD | FWRITE);
  125.             return (0);
  126.         }
  127.         v_lock(&sc->softc_lock, s);
  128.     }
  129.  
  130.     return (ENXIO);
  131. }
  132.  
  133. /*
  134.  * Line specific close routine.
  135.  * Detach the tty from the sl unit.
  136.  * Mimics part of ttyclose().
  137.  */
  138. slclose(tp)
  139.     struct tty *tp;
  140. {
  141.     register struct sl_softc *sc;
  142.     spl_t s;
  143.  
  144.     ttywflush(tp);
  145.     tp->t_line = 0;
  146.  
  147.     sc = dev_to_sc(tp->t_dev);
  148.     if (sc != NULL) {
  149.         s = p_lock(&sc->softc_lock, SPLIMP);
  150.         if_down(&sc->sc_if);
  151.         sc->sc_ttyp = NULL;
  152.         m_freem(sc->sc_mbuf);
  153.         sc->sc_mbuf = (struct mbuf *)NULL;
  154.         v_lock(&sc->softc_lock, s);
  155.     }
  156. }
  157.  
  158. /*
  159.  * Line specific (tty) ioctl routine.
  160.  * Provide a way to get the sl unit number.
  161.  */
  162. /* ARGSUSED */
  163. sltioctl(tp, cmd, data, flag)
  164.     struct tty *tp;
  165.     caddr_t data;
  166. {
  167.     register struct sl_softc *sc;
  168.     spl_t s;
  169.  
  170.     if (cmd == TIOCGETD) {
  171.         sc = dev_to_sc(tp->t_dev);
  172.         s = p_lock(&sc->softc_lock, SPLIMP);
  173.         *(int *)data = sc->sc_if.if_unit;
  174.         v_lock(&sc->softc_lock, s);
  175.         return (0);
  176.     }
  177.     return (-1);
  178. }
  179.  
  180. /*
  181.  * Queue a packet.  Start transmission if not active.
  182.  */
  183. sloutput(ifp, m, dst)
  184.     register struct ifnet *ifp;
  185.     register struct mbuf *m;
  186.     struct sockaddr *dst;
  187. {
  188.     register struct sl_softc *sc;
  189.     spl_t s;
  190.  
  191.     /*
  192.      * `Cannot happen' (see slioctl).  Someday we will extend
  193.      * the line protocol to support other address families.
  194.      */
  195.     if (dst->sa_family != AF_INET) {
  196.         printf("sl%d: af%d not supported\n", ifp->if_unit,
  197.             dst->sa_family);
  198.         m_freem(m);
  199.         return (EAFNOSUPPORT);
  200.     }
  201.  
  202.     sc = sl_softc[ifp->if_unit];
  203.     s = p_lock(&sc->softc_lock, SPLIMP);
  204.     if (sc->sc_ttyp == NULL) {
  205.         v_lock(&sc->softc_lock, s);
  206.         m_freem(m);
  207.         return (ENETDOWN);    /* sort of */
  208.     }
  209.     if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) {
  210.         v_lock(&sc->softc_lock, s);
  211.         m_freem(m);
  212.         return (EHOSTUNREACH);
  213.     }
  214.     if (IF_QFULL(&ifp->if_snd)) {
  215.         IF_DROP(&ifp->if_snd);
  216.         m_freem(m);
  217.         sc->sc_if.if_oerrors++;
  218.         printf("sl%d: output queue overflow\n", ifp->if_unit);
  219.         v_lock(&sc->softc_lock, s);
  220.         return (ENOBUFS);
  221.     }
  222.     IF_ENQUEUE(&ifp->if_snd, m);
  223.     if ((sc->sc_flags & SC_OACTIVE) == 0) {
  224.         v_lock(&sc->softc_lock, s);
  225.         slstart(sc->sc_ttyp);
  226.         return (0);
  227.     } 
  228.     v_lock(&sc->softc_lock, s);
  229.     return (0);
  230. }
  231.  
  232. /*
  233.  * Start output on interface.  Get another datagram
  234.  * to send from the interface queue and map it to
  235.  * the interface before starting output.
  236.  */
  237. slstart(tp)
  238.     register struct tty *tp;
  239. {
  240.     register struct sl_softc *sc;
  241.     register struct mbuf *m;
  242.     register int len;
  243.     register u_char *cp;
  244.     int flush, nd, np, n;
  245.     spl_t s;
  246.     struct mbuf *m2;
  247.     extern int cfreecount;
  248.  
  249.     sc = dev_to_sc(tp->t_dev);
  250.     for (;;) {
  251.         /*
  252.          * If there is more in the output queue, just send it now.
  253.          * We are being called in lieu of ttstart and must do what
  254.          * it would.
  255.          */
  256.         if (tp->t_outq.c_cc > 0)
  257.             ttstart(tp);
  258.         if (tp->t_outq.c_cc > SLIP_HIWAT)
  259.             return;
  260.  
  261.         /*
  262.          * This happens briefly when the line shuts down.
  263.          */
  264.         if (sc == NULL)
  265.             return;
  266.  
  267.  
  268.         s = p_lock(&sc->softc_lock, SPLIMP);
  269.  
  270.         /*
  271.          * If system is getting low on clists
  272.          * and we have something running already, stop here.
  273.          */
  274.         if (cfreecount < CLISTRESERVE + SLMTU && 
  275.             sc->sc_flags & SC_OACTIVE) {
  276.             v_lock(&sc->softc_lock, s);
  277.             return;
  278.         }
  279.  
  280.         /*
  281.          * Get a packet and send it to the interface.
  282.          */
  283.         IF_DEQUEUE(&sc->sc_if.if_snd, m);
  284.         if (m == NULL) {
  285.             if (tp->t_outq.c_cc == 0)
  286.                 sc->sc_flags &= ~SC_OACTIVE;
  287.             v_lock(&sc->softc_lock, s);
  288.             return;
  289.         }
  290.         flush = !(sc->sc_flags & SC_OACTIVE);
  291.         sc->sc_flags |= SC_OACTIVE;
  292.         v_lock(&sc->softc_lock, s);
  293.  
  294.         /*
  295.          * The extra FRAME_END will start up a new packet, and thus
  296.          * will flush any accumulated garbage.  We do this whenever
  297.          * the line may have been idle for some time.
  298.          */
  299.         if (flush)
  300.             (void) putc(FRAME_END, &tp->t_outq);
  301.  
  302.         while (m) {
  303.             cp = mtod(m, u_char *);
  304.             len = m->m_len;
  305.             while (len > 0) {
  306.                 /*
  307.                  * Find out how many bytes in the string we can
  308.                  * handle without doing something special.
  309.                  */
  310.                 nd = locc(FRAME_ESCAPE, len, cp);
  311.                 np = locc(FRAME_END, len, cp);
  312.                 n = len - MAX(nd, np);
  313.                 if (n) {
  314.                     /*
  315.                      * Put n characters at once
  316.                      * into the tty output queue.
  317.                      */
  318.                     if (b_to_q((char *)cp, n, &tp->t_outq))
  319.                         break;
  320.                     len -= n;
  321.                     cp += n;
  322.                 }
  323.                 /*
  324.                  * If there are characters left in the mbuf,
  325.                  * the first one must be special..
  326.                  * Put it out in a different form.
  327.                  */
  328.                 if (len) {
  329.                     if (putc(FRAME_ESCAPE, &tp->t_outq))
  330.                         break;
  331.                     if (putc(*cp == FRAME_ESCAPE ?
  332.                        TRANS_FRAME_ESCAPE : TRANS_FRAME_END,
  333.                        &tp->t_outq)) {
  334.                         (void) unputc(&tp->t_outq);
  335.                         break;
  336.                     }
  337.                     cp++;
  338.                     len--;
  339.                 }
  340.             }
  341.             MFREE(m, m2);
  342.             m = m2;
  343.         }
  344.  
  345.         if (putc(FRAME_END, &tp->t_outq)) {
  346.             /*
  347.              * Not enough room.  Remove a char to make room
  348.              * and end the packet normally.
  349.              * If you get many collisions (more than one or two
  350.              * a day) you probably do not have enough clists
  351.              * and you should increase "nclist" in param.c.
  352.              */
  353.             (void) unputc(&tp->t_outq);
  354.             (void) putc(FRAME_END, &tp->t_outq);
  355.             s = p_lock(&sc->softc_lock, SPLIMP);
  356.             sc->sc_if.if_collisions++;
  357.             printf("sl%d: clist overflow\n", sc->sc_if.if_unit);
  358.             v_lock(&sc->softc_lock, s);
  359.         } else {
  360.             s = p_lock(&sc->softc_lock, SPLIMP);
  361.             sc->sc_if.if_opackets++;
  362.             v_lock(&sc->softc_lock, s);
  363.         }
  364.     }
  365. }
  366.  
  367. slinit(sc)
  368.     register struct sl_softc *sc;
  369. {
  370.     struct mbuf *m;
  371.  
  372.     if (sc->sc_mbuf == (struct mbuf *)NULL) {
  373.         m = m_getcl(M_DONTWAIT, MT_DATA);
  374.         if (m) {
  375.             m->m_len = MCLEN;
  376.             sc->sc_mbuf = m;
  377.             sc->sc_mp = mtod(m, char *);
  378.         } else {
  379.             printf("sl%d: can't allocate mbuf cluster\n",sc->sc_if.if_unit);
  380.             sc->sc_if.if_flags &= ~IFF_UP;
  381.             return (0);
  382.         }
  383.     }
  384.     return (1);
  385. }
  386.  
  387. /*
  388.  * Copy data buffer to mbuf chain; add ifnet pointer ifp.
  389.  */
  390. struct mbuf *
  391. sl_btom(bufp, count, ifp)
  392.     register u_char *bufp;
  393.     register int count;
  394.     struct ifnet *ifp;
  395. {
  396.     register struct mbuf *m;
  397.     struct mbuf *mhead;
  398.  
  399.     m = m_getm(M_DONTWAIT, MT_DATA,
  400.             howmany((count+sizeof(struct ifnet*)), MLEN));
  401.  
  402.     if ((mhead = m) != (struct mbuf *)NULL) {
  403.         mhead->m_off += sizeof(struct ifnet *);
  404.         m->m_len = (count > IFPMLEN) ? IFPMLEN : count;
  405.         bcopy((caddr_t)bufp, mtod(m, caddr_t), (unsigned)m->m_len);
  406.         count -= m->m_len;
  407.         bufp += m->m_len;
  408.         m = m->m_next;
  409.  
  410.         while (count) {
  411.             m->m_off = MMINOFF;
  412.             m->m_len = (count > MLEN) ? MLEN : count;
  413.             bcopy((caddr_t)bufp, mtod(m, caddr_t),
  414.                         (unsigned)m->m_len);
  415.             count -= m->m_len;
  416.             bufp += m->m_len;
  417.             m = m->m_next;
  418.         }
  419.  
  420.         /* Copy in ifnet struct pointer info */
  421.         mhead->m_off -= sizeof(struct ifnet *);
  422.         mhead->m_len += sizeof(struct ifnet *);
  423.         *mtod(mhead, struct ifnet **) = ifp;
  424.     }
  425.     
  426.     return(mhead);
  427. }
  428.  
  429.  
  430. /*
  431.  * tty interface receiver interrupt.
  432.  */
  433. slinput(c, tp)
  434.     register int c;
  435.     register struct tty *tp;
  436. {
  437.     register struct sl_softc *sc;
  438.     register struct mbuf *m;
  439.     spl_t s;
  440.  
  441.  
  442.     l.cnt.v_ttyin++;
  443.     sc = dev_to_sc(tp->t_dev);
  444.     if (sc == NULL)
  445.         return;
  446.  
  447.     c &= 0xff;
  448.     s = p_lock(&sc->softc_lock, SPLIMP);
  449.     if (sc->sc_flags & SC_ESCAPED) {
  450.         sc->sc_flags &= ~SC_ESCAPED;
  451.         switch (c) {
  452.  
  453.         case TRANS_FRAME_ESCAPE:
  454.             c = FRAME_ESCAPE;
  455.             break;
  456.  
  457.         case TRANS_FRAME_END:
  458.             c = FRAME_END;
  459.             break;
  460.  
  461.         default:
  462.             sc->sc_if.if_ierrors++;
  463.             printf("sl%d: framing error\n", sc->sc_if.if_unit);
  464.             sc->sc_mp = mtod(sc->sc_mbuf, char *);
  465.             sc->sc_ilen = 0;
  466.             v_lock(&sc->softc_lock, s);
  467.             return;
  468.         }
  469.     } else {
  470.         switch (c) {
  471.  
  472.         case FRAME_END:
  473.             if (sc->sc_ilen == 0){     /* ignore */
  474.                 v_lock(&sc->softc_lock, s);
  475.                 return;
  476.             }
  477.             m = sl_btom( mtod(sc->sc_mbuf, u_char *), sc->sc_ilen, 
  478.                      &sc->sc_if );
  479.             if (m == (struct mbuf *)NULL) {
  480.                 sc->sc_if.if_ierrors++;
  481.                 printf("sl%d: out of memory\n", sc->sc_if.if_unit);
  482.                 v_lock(&sc->softc_lock, s);
  483.                 return;
  484.             }
  485.             sc->sc_mp = mtod(sc->sc_mbuf, char *);
  486.             sc->sc_ilen = 0;
  487.             sc->sc_if.if_ipackets++;
  488.             if (IF_QFULL(&ipintrq)) {
  489.                 IF_DROP(&ipintrq);
  490.                 sc->sc_if.if_ierrors++;
  491.                 printf("sl%d: input queue overflow\n", sc->sc_if.if_unit);
  492.                 v_lock(&sc->softc_lock, s);
  493.                 m_freem(m);
  494.             } else {
  495.                 IF_ENQUEUE(&ipintrq, m);
  496.                 v_lock(&sc->softc_lock, s);
  497.                 schednetisr(NETISR_IP);
  498.             }
  499.             return;
  500.  
  501.         case FRAME_ESCAPE:
  502.             sc->sc_flags |= SC_ESCAPED;
  503.             v_lock(&sc->softc_lock, s);
  504.             return;
  505.         }
  506.     }
  507.     if (++sc->sc_ilen > SLMTU) {
  508.         sc->sc_if.if_ierrors++;
  509.         printf("sl%d: frame overflow\n", sc->sc_if.if_unit);
  510.         sc->sc_mp = mtod(sc->sc_mbuf, char *);
  511.         sc->sc_ilen = 0;
  512.         v_lock(&sc->softc_lock, s);
  513.         return;
  514.     }
  515.     *sc->sc_mp++ = c;
  516.     v_lock(&sc->softc_lock, s);
  517. }
  518.  
  519. /*
  520.  * Process an ioctl request.
  521.  */
  522. slioctl(ifp, cmd, data)
  523.     register struct ifnet *ifp;
  524.     int cmd;
  525.     caddr_t data;
  526. {
  527.     register struct ifaddr *ifa = (struct ifaddr *)data;
  528.     spl_t s; 
  529.     int error = 0;
  530.  
  531.     s = p_lock(&ifp->if_snd.ifq_lock, SPLIMP);
  532.     switch (cmd) {
  533.  
  534.     case SIOCSIFADDR:
  535.         if (ifa->ifa_addr.sa_family == AF_INET)
  536.             ifp->if_flags |= IFF_UP;
  537.         else
  538.             error = EAFNOSUPPORT;
  539.         break;
  540.  
  541.     case SIOCSIFDSTADDR:
  542.         if (ifa->ifa_addr.sa_family != AF_INET)
  543.             error = EAFNOSUPPORT;
  544.         break;
  545.  
  546.     default:
  547.         error = EINVAL;
  548.     }
  549.     v_lock(&ifp->if_snd.ifq_lock, s);
  550.     return (error);
  551. }
  552.  
  553. /*
  554.  * locate mask
  555.  */
  556. locc(mask, size, cp)
  557.         register u_char mask;
  558.         u_int size;
  559.         register u_char *cp;
  560. {
  561.         register u_char *end = &cp[size];
  562.  
  563.         while (cp < end && *cp != mask)
  564.                 cp++;
  565.         return (end - cp);
  566. }
  567.  
  568. /*
  569.  * locate sl_softc for device
  570.  */
  571. struct sl_softc *
  572. dev_to_sc( dev )
  573.     register dev_t dev;
  574. {
  575.     register int i;
  576.  
  577.     for (i=0; sl_softc[i] != NULL; i++) 
  578.         if (sl_softc[i]->sc_dev == dev)
  579.             return(sl_softc[i]);
  580.     return(NULL);
  581. }
  582.